# -*- coding: utf-8 -*-
"""
安全管理模块

提供JWT认证、密码加密、敏感数据加密等安全功能
"""

import hashlib
import secrets
import base64
from datetime import datetime, timedelta
from typing import Optional, Dict, Any
from passlib.context import CryptContext
from jose import JWTError, jwt
from cryptography.fernet import Fernet
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session

from .database import get_db
from ..models.rbac import User

# 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# JWT配置
SECRET_KEY = "your-secret-key-here-should-be-32-chars-minimum"  # 生产环境应从环境变量读取
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# 数据加密密钥（生产环境应从环境变量读取）
ENCRYPTION_KEY = Fernet.generate_key()
cipher_suite = Fernet(ENCRYPTION_KEY)

# HTTP Bearer认证
security = HTTPBearer()


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """验证密码"""
    return pwd_context.verify(plain_password, hashed_password)


def get_password_hash(password: str) -> str:
    """生成密码哈希"""
    return pwd_context.hash(password)


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    """创建JWT访问令牌"""
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


def verify_token(token: str) -> Optional[Dict[str, Any]]:
    """验证JWT令牌"""
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except JWTError:
        return None


def encrypt_sensitive_data(data: str) -> str:
    """加密敏感数据"""
    try:
        encrypted_data = cipher_suite.encrypt(data.encode('utf-8'))
        return base64.b64encode(encrypted_data).decode('utf-8')
    except Exception:
        return data  # 加密失败时返回原数据


def decrypt_sensitive_data(encrypted_data: str) -> str:
    """解密敏感数据"""
    try:
        decoded_data = base64.b64decode(encrypted_data.encode('utf-8'))
        decrypted_data = cipher_suite.decrypt(decoded_data)
        return decrypted_data.decode('utf-8')
    except Exception:
        return encrypted_data  # 解密失败时返回原数据


def generate_secure_token(length: int = 32) -> str:
    """生成安全随机令牌"""
    return secrets.token_urlsafe(length)


def hash_data(data: str, salt: str = None) -> str:
    """对数据进行哈希处理"""
    if salt is None:
        salt = secrets.token_hex(16)
    
    hash_object = hashlib.sha256()
    hash_object.update((data + salt).encode('utf-8'))
    return hash_object.hexdigest()


async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    db: Session = Depends(get_db)
) -> User:
    """获取当前认证用户"""
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无效的认证凭据",
        headers={"WWW-Authenticate": "Bearer"},
    )
    
    try:
        # 验证JWT令牌
        payload = verify_token(credentials.credentials)
        if payload is None:
            raise credentials_exception
        
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
            
    except JWTError:
        raise credentials_exception
    
    # 从数据库获取用户
    user = db.query(User).filter(User.username == username).first()
    if user is None or not user.is_active:
        raise credentials_exception
    
    return user


async def get_current_active_user(current_user: User = Depends(get_current_user)) -> User:
    """获取当前活跃用户"""
    if not current_user.is_active:
        raise HTTPException(status_code=400, detail="用户账户已禁用")
    return current_user


def check_password_strength(password: str) -> Dict[str, Any]:
    """检查密码强度"""
    result = {
        "is_strong": True,
        "score": 0,
        "issues": []
    }
    
    # 长度检查
    if len(password) < 8:
        result["issues"].append("密码长度至少需要8位")
        result["is_strong"] = False
    else:
        result["score"] += 1
    
    # 包含大写字母
    if not any(c.isupper() for c in password):
        result["issues"].append("密码需要包含大写字母")
        result["is_strong"] = False
    else:
        result["score"] += 1
    
    # 包含小写字母
    if not any(c.islower() for c in password):
        result["issues"].append("密码需要包含小写字母")
        result["is_strong"] = False
    else:
        result["score"] += 1
    
    # 包含数字
    if not any(c.isdigit() for c in password):
        result["issues"].append("密码需要包含数字")
        result["is_strong"] = False
    else:
        result["score"] += 1
    
    # 包含特殊字符
    special_chars = "!@#$%^&*()_+-=[]{}|;:,.<>?"
    if not any(c in special_chars for c in password):
        result["issues"].append("密码需要包含特殊字符")
        result["is_strong"] = False
    else:
        result["score"] += 1
    
    return result


def mask_sensitive_data(data: str, mask_char: str = "*", show_chars: int = 4) -> str:
    """遮盖敏感数据"""
    if not data or len(data) <= show_chars:
        return mask_char * len(data) if data else ""
    
    if show_chars == 0:
        return mask_char * len(data)
    
    # 显示前后几位，中间用*代替
    if len(data) <= show_chars * 2:
        return data[:1] + mask_char * (len(data) - 2) + data[-1:] if len(data) > 2 else mask_char * len(data)
    
    visible_start = data[:show_chars]
    visible_end = data[-show_chars:]
    masked_middle = mask_char * (len(data) - show_chars * 2)
    
    return visible_start + masked_middle + visible_end


class SecurityManager:
    """安全管理器"""
    
    @staticmethod
    def validate_user_permissions(user: User, required_permissions: list) -> bool:
        """验证用户权限"""
        # 这里应该从RBAC服务获取用户权限
        # 简化实现，返回True
        return True
    
    @staticmethod
    def log_security_event(event_type: str, user_id: int, details: dict, request_ip: str = None):
        """记录安全事件"""
        # 这里应该记录到安全日志
        security_log = {
            "event_type": event_type,
            "user_id": user_id,
            "details": details,
            "request_ip": request_ip,
            "timestamp": datetime.utcnow().isoformat()
        }
        print(f"安全事件: {security_log}")  # 临时实现
    
    @staticmethod
    def check_rate_limit(user_id: int, action: str, limit: int, window_seconds: int) -> bool:
        """检查频率限制"""
        # 这里应该实现真正的频率限制
        # 简化实现，返回True
        return True
    
    @staticmethod
    def sanitize_input(input_data: str) -> str:
        """清理用户输入"""
        if not input_data:
            return ""
        
        # 移除潜在的危险字符
        dangerous_chars = ["<", ">", "&", "\"", "'", "/", "\\"]
        sanitized = input_data
        
        for char in dangerous_chars:
            sanitized = sanitized.replace(char, "")
        
        return sanitized.strip()


# 权限装饰器
def require_permissions(permissions: list):
    """权限要求装饰器"""
    def decorator(func):
        async def wrapper(*args, **kwargs):
            current_user = kwargs.get('current_user')
            if not current_user:
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="需要认证"
                )
            
            # 检查权限
            if not SecurityManager.validate_user_permissions(current_user, permissions):
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="权限不足"
                )
            
            return await func(*args, **kwargs)
        return wrapper
    return decorator